package com.mjk.common.core.jdbc.service.plus.provider.impl.wrap.mongodb;


import com.mjk.common.base.model.BaseEntity;
import com.mjk.common.base.model.BaseExample;
import com.mjk.common.core.jdbc.annotation.ArcSharding;
import com.mjk.common.core.jdbc.bean.Criterion;
import com.mjk.common.core.jdbc.datasource.CommonDataSourceAutoConf;
import com.mjk.common.core.jdbc.datasource.ShardingDataSouceAutoConf;
import com.mjk.common.core.jdbc.service.plus.provider.abstractor.IWrapperProvider;
import com.mjk.common.core.jdbc.util.TableUtils;
import com.mjk.common.core.jdbc.util.provider.SqlProvider;
import com.mjk.common.tools.gson.GsonUtils;
import com.mjk.common.tools.springextend.BeeSpringBean;
import com.mjk.common.util.BeanUtils;
import com.mjk.common.util.ObjectUtils;
import com.mjk.common.util.ReflectionUtils;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.UpdateResult;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * mongodb
 * 
 * @author Administrator
 *
 */
public class MongodbProvider implements IWrapperProvider {

	private MongoCollection<Document> getCollection(BaseEntity entity) {
		ShardingDataSouceAutoConf sharding = BeeSpringBean.getBean(ShardingDataSouceAutoConf.class);
		String dataSource = TableUtils.getDataSource(entity);
		DataSource source;
		if (!ObjectUtils.isEmpty(sharding)) {
			source = sharding.getDataSourceMap().get(dataSource);
		} else {
			CommonDataSourceAutoConf common = BeeSpringBean.getBean(CommonDataSourceAutoConf.class);
			source = Objects.requireNonNull(common).getDataSourceMap().get(dataSource);
		}
		if (source instanceof MongoDataSource mds) {
			MongoClient client = mds.getClient();
			MongoDatabase dataBase = client.getDatabase(TableUtils.getDataSource(entity));
			return dataBase.getCollection(TableUtils.getTableName(entity));
		} else {
			return null;
		}
	}

	/**
	 * 获取数量
	 */
	@Override
	public String countByExample(Map<String, Object> map) {
		BaseExample example = (BaseExample) map.get("example");
        BaseEntity entity = SqlProvider.getEntityFromExample(example);
		MongoCollection<Document> collection = getCollection(entity);
		if(null == collection) {
			return null;
		}
		Bson bson = getQueryCondition(example);
		if(null == bson) {
			return collection.countDocuments()+"";
		}else {
			return collection.countDocuments(bson)+"";
		}
	}
	/**
	 * 根据条件删除
	 */
	@Override
	public String deleteByExample(Map<String, Object> map) {
		BaseExample example = (BaseExample) map.get("example");
        BaseEntity entity = SqlProvider.getEntityFromExample(example);
		MongoCollection<Document> collection = getCollection(entity);
		if(null == collection) {
			return null;
		}
		collection.deleteMany(Objects.requireNonNull(getQueryCondition(example)));
		return "1";
	}
	/**
	 * 插入
	 */
	@Override
	public String insert(Map<String, Object> map) {
		BaseEntity app = (BaseEntity) map.get("dto");
		MongoCollection<Document> collection = getCollection(app);
		if(null == collection) {
			return null;
		}
		Document docment = new Document(BeanUtils.beanToMap(app));
		collection.insertOne(docment);
		return "1";
	}
	/**
	 * 查询
	 */
	@Override
	public String selectByExample(Map<String, Object> map) {
		BaseExample example = (BaseExample) map.get("example");
        BaseEntity entity = SqlProvider.getEntityFromExample(example);
		MongoCollection<Document> collection = getCollection(entity);
		if(null == collection) {
			return null;
		}
		Bson bson = getQueryCondition(example);
		FindIterable<Document> documents;
		if(null == bson) {
			documents = collection.find();
		}else {
			documents = collection.find(bson);
		}		
		List<Map<String,Object>> results = new ArrayList<>();
		documents.forEach(results::add);
		return GsonUtils.bean2Json(results);
	}
	/**
	 * 更新数据
	 */
	@Override
	public String updateByExampleSelective(Map<String, Object> map) {
		BaseEntity app = (BaseEntity) map.get("dto");
        BaseExample example = (BaseExample) map.get("example");
        MongoCollection<Document> collection = getCollection(app);
        if(null == collection) {
			return null;
		}
        UpdateResult result = collection.updateMany(Objects.requireNonNull(getQueryCondition(example)), new Document("$set",new Document(BeanUtils.beanToMap(app))));
		return result.getMatchedCount()+"";//返回修改条数
	}
	
	@Override
	public String getTabName(ArcSharding arc) {
		return arc.table();
	}

	/**
	 * example解析为条件
	 *
     */
	public static Bson getQueryCondition(BaseExample k) {
		List<Bson> filters = new ArrayList<>();
		@SuppressWarnings("unchecked")
		List<Object> list = (List<Object>) ReflectionUtils.getFieldValue(k, "oredCriteria");
		for (Object o : list) {
			@SuppressWarnings("unchecked")
			List<Criterion> criterions = (List<Criterion>) ReflectionUtils.getFieldValue(o, "criteria");
			for (Criterion criterion : criterions) {
				if (criterion.getValue() == null) {
					//do notiong
                } else  {
					if (criterion.getCondition().contains("between")) {
						filters.add(Filters.gt(criterion.getCondition() + "start", criterion.getValue().toString()));
						filters.add(Filters.lt(criterion.getCondition() + "end", criterion.getSecondValue()));
					} else if (criterion.getCondition().contains("<>")) {
						String key = criterion.getCondition().replace("<>", "").trim();
						filters.add(Filters.ne(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains(">")) {
						String key = criterion.getCondition().replace(">", "").trim();
						filters.add(Filters.gt(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains(">=")) {
						String key = criterion.getCondition().replace(">=", "").trim();
						filters.add(Filters.gte(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains("<")) {
						String key = criterion.getCondition().replace("<", "").trim();
						filters.add(Filters.lt(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains("<=")) {
						String key = criterion.getCondition().replace("<=", "").trim();
						filters.add(Filters.lte(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains("in")) {
						String key = criterion.getCondition().replace("in", "").trim();
						filters.add(Filters.in(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains("not in")) {
						String key = criterion.getCondition().replace("not in", "").trim();
						filters.add(Filters.nin(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains("like")) {
						String key = criterion.getCondition().replace("like", "").trim();
						filters.add(Filters.regex(key, criterion.getValue().toString()));
					} else if (criterion.getCondition().contains("=")) {
						String key = criterion.getCondition().replace("=", "").trim();
						filters.add(Filters.eq(key, criterion.getValue().toString()));
					}
				}
			}
		}
		if(CollectionUtils.isEmpty(filters)) {
			return null;
		}
        return Filters.and(filters);
	}

}
